/*
 * Copyright (c) 2013, FPX and/or its affiliates. All rights reserved.
 * Use, Copy is subject to authorized license.
 */
package com.pyip.simpleioc.beans.definition.factory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Map.Entry;

import com.pyip.simpleioc.beans.definition.BeanDefinition;
import com.pyip.simpleioc.beans.definition.BeanDefinitionException;

/**
 * @author yepeng
 * @date 2015年11月6日
 */
public class BeansFactoryImpl implements BeansFactory {
    @Override
    public void doDefinition(BeanDefinition beanDefinition) {
        if (beanDefinition == null) {
            throw new NullPointerException("参数beanDefinition不能为空");
        }
        if (beanDefinition.getObject() != null) {
            throw new BeanDefinitionException("不允许重复实例化Bean对象");
        }

        Object obj = null;
        try {
            String beanClass = beanDefinition.getBeanClass();
            Class<?> clazz = Class.forName(beanClass);
            obj = clazz.newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            throw new BeanDefinitionException(e);
        }

        setPropertyValues(beanDefinition, obj);

        beanDefinition.setObject(obj);
    }

    @Override
    public void doDefinition(Map<String, BeanDefinition> beanDefinitionMap) {
        for (Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            doDefinition(entry.getValue());
        }
    }

    private void setPropertyValues(BeanDefinition beanDefinition, Object obj) {
        if (beanDefinition.getPropertyValues() != null) {
            Class<?> clazz = obj.getClass();
            for (Entry<String, Object> entry : beanDefinition.getPropertyValues().getPropertyValues().entrySet()) {
                String key = entry.getKey();
                Method setMethod;
                try {
                    setMethod = getSetMethod(clazz, key, String.class);
                    setMethod.invoke(obj, entry.getValue());
                } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                    throw new BeanDefinitionException(e);
                }
            }
        }
    }

    private Method getSetMethod(Class<?> clazz, String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException {
        name = name.substring(0, 1).toUpperCase() + name.substring(1);
        return clazz.getMethod("set" + name, parameterTypes);
    }
}
